# -*- coding: utf-8 -*-

from datetime import datetime
from cmdb import db
from cmdb import login_manager
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from flask import current_app
from .permissons import permission_list


class Role(db.Model):
    """角色表，可以按照角色分配相应的权限"""
    __tablename__ = 'roles'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    default = db.Column(db.Boolean, default=False, index=True)
    permissions = db.Column(db.Integer)
    users = db.relationship('User', backref='role', lazy='dynamic')

    @staticmethod
    def insert_roles():
        roles = permission_list.keys()
        for r in roles:
            role = Role.query.filter_by(name=r).first()
            if role is None:
                role = Role(name=r)
            role.permissions = permission_list[r]
            if r == u'普通用户':
                role.default = True
            db.session.add(role)
        db.session.commit()

    def __unicode__(self):
        return '<Role %r>' % self.name


class User(UserMixin, db.Model):
    """用户表，使用flask-login，需要继承UserMixin"""
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), unique=True, index=True)
    name = db.Column(db.String(64))
    password_hash = db.Column(db.String(128))
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
    permissions = db.Column(db.Integer, default=0)
    create_since = db.Column(db.DATETIME(), default=datetime.now())
    last_login = db.Column(db.DATETIME(), default=datetime.now())
    email = db.Column(db.String(64), unique=True, index=True)
    phone = db.Column(db.String(32))

    def __init__(self, **kwargs):
        super(User, self).__init__(**kwargs)
        if self.role is None:
            if self.username == 'admin':
                self.role = Role.query.filter_by(permissions=0xffff).first()
            if self.role is None:
                self.role = Role.query.filter_by(default=True).first()

    @property
    def password(self):
        raise AttributeError('password is not a readable attribute.')

    @password.setter
    def password(self, password):
        """设置用户密码"""
        self.password_hash = generate_password_hash(password)

    def verify_password(self, password):
        """验证密码"""
        return check_password_hash(self.password_hash, password)

    def can(self, permissions):
        """权限判定"""
        role_result = self.role is not None and (self.role.permissions & permissions) == permissions
        user_result = self.permissions is not None and (self.permissions & permissions) == permissions
        return role_result and user_result

    def is_administrator(self):
        """判断用户是否是管理员"""
        return self.can(permission_list[u'超级管理员'])

    def ping(self):
        """刷新用户最后一次登录时间"""
        self.last_login = datetime.now()
        db.session.add(self)
        db.session.commit()

    def to_json(self):
        """生成用户信息列表，以json的格式"""
        json_user = {
            'username': self.username,
            'name': self.name,
            'create_since': self.create_since,
            'last_login': self.last_login,
            'email': self.email,
            'role': self.role.name,
            'permission': self.permissions,
            'phone': self.phone
        }
        return json_user

    def generate_auth_token(self, expiration):
        """生成用户登录的token，可指定失效时间"""
        s = Serializer(current_app.config['SECRET_KEY'],
                       expires_in=expiration)
        return s.dumps({'id', self.id}).decode('ascii')

    @staticmethod
    def verify_auth_token(token):
        s = Serializer(current_app.config['SECRET_KEY'])
        try:
            data = s.loads(token)
        except:
            return None
        return User.query.get(data['id'])

    def __unicode__(self):
        return '<User %r>' % self.username


@login_manager.user_loader
def load_user(user_id):
    """加载用户的回调函数，如果存在用户id则返回User对象，否则返回None"""
    return User.query.get(int(user_id))


class ServerRoom(db.Model):
    """服务器机房，可以存储名称，地址，管理员，管理员联系方式"""
    __tablename__ = 'server_room'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True, nullable=False)
    address = db.Column(db.String(128), nullable=False)
    contacts = db.Column(db.String(64))
    contacts_tel = db.Column(db.String(64), nullable=False)
    ec_list = db.relationship('EquipmentCabinet', backref='server_room', lazy='dynamic')

    def to_json(self):
        """生成json格式的数据"""
        json_data = {
            'id': self.id,
            'name': self.name,
            'address': self.address,
            'contacts': self.contacts,
            'contacts_tel': self.contacts_tel,
        }
        return json_data


class EquipmentCabinet(db.Model):
    """机柜，可以存储名称，位置，类型，管理员，租用开始和结束时间"""
    __tablename__ = 'equipment_cabinet'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True, nullable=False, index=True)
    location = db.Column(db.String(64), nullable=False)
    type = db.Column(db.Integer, nullable=False)
    server_room_id = db.Column(db.Integer, db.ForeignKey(ServerRoom.id))
    start_date = db.Column(db.DATE)
    expire_date = db.Column(db.DATE)
    device_list = db.relationship('Device', backref='ec', lazy='dynamic')

    def to_json(self):
        """生成json格式的数据"""
        json_data = {
            'id': self.id,
            'name': self.name,
            'location': self.location,
            'type': self.type,
            'server_room': self.server_room.name,
            'start_date': self.start_date,
            'expire_date': self.expire_date,
        }
        return json_data


class Device(db.Model):
    """物理设备，可以存储名称，机房id，开始槽位，结束槽位, 设备类型， 设备品牌， 设备序列号"""
    __tablename__ = 'device'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(128), unique=True, nullable=False, index=True)
    ec_id = db.Column(db.Integer, db.ForeignKey(EquipmentCabinet.id))
    start_slot = db.Column(db.Integer, nullable=False)
    end_slot = db.Column(db.Integer, nullable=False)
    device_type = db.Column(db.Integer, nullable=False)
    device_brand = db.Column(db.Integer, nullable=False)
    sn = db.Column(db.String, nullable=False)

    def to_json(self):
        """生成json格式的数据"""
        json_data = {
            'id': self.id,
            'name': self.name,
            'ec': self.ec.name,
            'start_slot': self.start_slot,
            'end_slot': self.end_slot,
            'device_type': self.device_type,
            'device_brand': self.device_brand,
            'sn': self.sn,
        }
        return json_data


class IpSubnet(db.Model):
    """IP网段，存储名称，掩码，起止IP，"""
    __tablename__ = 'ip_subnet'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), nullable=False, unique=True, index=True)
    netmask = db.Column(db.String(64), nullable=False)
    start_ip = db.Column(db.String(64), nullable=False)
    end_ip = db.Column(db.String(64))
    ip_list = db.relationship('IpPool', backref='subnet', lazy='dynamic')

    def to_json(self):
        """生成json格式的数据"""
        json_data = {
            'id': self.id,
            'name': self.name,
            'netmask': self.netmask,
            'start_ip': self.start_ip,
            'end_ip': self.end_ip,
        }
        return json_data


class Platform(db.Model):
    """应用平台，定义平台名称，项目负责人，研发接口人"""
    __tablename__ = 'platform'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(128), nullable=False, unique=True, index=True)
    pm = db.Column(db.String(32), nullable=False)
    pm_tel = db.Column(db.String(32), nullable=False)
    dm = db.Column(db.String(32), nullable=False)
    dm_tel = db.Column(db.String(32), nullable=False)
    server_list = db.relationship('Server', backref='platform', lazy='dynamic')

    def to_json(self):
        """生成json格式的数据"""
        json_data = {
            'id': self.id,
            'name': self.name,
            'pm': self.pm,
            'pm_tel': self.pm_tel,
            'dm': self.dm,
            'dm_tel': self.dm_tel,
        }
        return json_data


class Server(db.Model):
    """服务器列表，定义是什么操作系统，有什么IP，什么版本等等"""
    __tablename__ = 'server'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(128), nullable=False, unique=True, index=True)
    os = db.Column(db.Integer, nullable=False)
    version = db.Column(db.String(32), nullable=False)
    ip_list = db.relationship('IpPool', backref='server', lazy='dynamic')
    service_list = db.relationship('Service', backref='server', lazy='dynamic')
    platform_id = db.Column(db.Integer, db.ForeignKey(Platform.id))
    device_id = db.Column(db.Integer, db.ForeignKey(Device.id))
    status = db.Column(db.Boolean, default=False)

    def to_json(self):
        """生成json格式的数据"""
        json_data = {
            'id': self.id,
            'name': self.name,
            'os': self.os,
            'version': self.version,
            'platform': self.platform.name,
            'device': self.device,
            'status': '上线' if self.status else '下线'
        }
        return json_data


class IpPool(db.Model):
    """IP表，可以定义IP表的用途"""
    __tablename__ = 'ip_pool'
    id = db.Column(db.Integer, primary_key=True)
    ip = db.Column(db.String(64), nullable=False, unique=True, index=True)
    is_vip = db.Column(db.Boolean, default=False)
    gateway = db.Column(db.String(64), nullable=False)
    subnet_id = db.Column(db.Integer, db.ForeignKey(IpSubnet.id))
    server_id = db.Column(db.Integer, db.ForeignKey(Server.id))

    def to_json(self):
        """生成json格式的数据"""
        json_data = {
            'id': self.id,
            'ip': self.ip,
            'is_vip': 'VIP' if self.is_vip else 'IP',
            'gateway': self.gateway,
            'subnet': self.subnet,
            'server': self.server,
        }
        return json_data


class Service(db.Model):
    """服务列表，定义服务名称，软件名称，软件版本"""
    __tablename__ = 'service'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), nullable=False)
    software = db.Column(db.String(64), nullable=False)
    version = db.Column(db.String(32), nullable=False)
    port = db.Column(db.String(32))
    server_id = db.Column(db.Integer, db.ForeignKey(Server.id))

    def to_json(self):
        """生成json格式的数据"""
        json_data = {
            'id': self.id,
            'name': self.name,
            'software': self.software,
            'version': self.version,
            'port': self.port,
            'server': self.server.name
        }
        return json_data


class NetworkPolicy(db.Model):
    """网络策略列表，定义源平台，源地址，源端口，目的平台，目的地址，目的端口，申请人"""
    __tablename__ = 'network_policy'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), nullable=False)
    src_platform = db.Column(db.String(64), nullable=False)
    src_ip = db.Column(db.String(32), nullable=False)
    src_port = db.Column(db.String(12), nullable=False)
    dst_platform = db.Column(db.String(64), nullable=False)
    dst_ip = db.Column(db.String(32), nullable=False)
    dst_port = db.Column(db.String(12), nullable=False)
    ask_user = db.Column(db.String(12), nullable=False)

    def to_json(self):
        """生成json格式的数据"""
        json_data = {
            'id': self.id,
            'name': self.name,
            'src_platform': self.src_platform,
            'src_ip': self.src_ip,
            'src_port': self.src_port,
            'dst_platform': self.dst_platform,
            'dst_ip': self.dst_ip,
            'dst_port': self.dst_port,
            'ask_user': self.ask_user
        }
        return json_data
